package com.gzhryc.common.event;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.gzhryc.common.logging.Logger;

public class TriggerService {
	
	static Logger log = Logger.getLogger(TriggerService.class);
	
	static TriggerService self;
	
	public static TriggerService get() {
		if(self == null) {
			self = new TriggerService();
		}
		return self;
	}

	ConcurrentHashMap<String,DataLock> DataLockMap = new ConcurrentHashMap<String,DataLock>();
	
	Timer timer = new Timer();
	
	public void setTriggerLock(String key) {
		DataLock dataLock = DataLockMap.remove(key);
		if(dataLock != null) {
			dataLock.shop();
		}
		dataLock = new DataLock();
		DataLockMap.put(key, dataLock);
	}
	
	/**
	 * 设置触发锁
	 */
	public void setTriggerLock(String key,Long time,TimeUnit unit) {
		DataLock dataLock = DataLockMap.remove(key);
		if(dataLock != null) {
			dataLock.shop();
		}
		dataLock = new DataLock();
		DataLockMap.put(key, dataLock);
		ExpireCheckTask task = new ExpireCheckTask(key); 
		timer.schedule(task, unit.toMillis(time));
	}
	
	/**
	 * 检查是否存在触发锁
	 * @param key
	 * @return
	 */
	public boolean hasTriggerLock(String key) {
		return DataLockMap.containsKey(key);
	}
	
	public void removeTriggerLock(String key) {
		DataLockMap.remove(key);
		log.info("移除Key："+key+"，当前触发锁数量：" + DataLockMap.size());
	}
	
	/**
	 * 获取数据
	 * @param key
	 * @param time
	 * @param unit
	 * @return
	 */
	public Object getData(String key,Long time,TimeUnit unit){
		return getData(key,time,unit,true);
	}
	
	public Object getData(String key,Long time,TimeUnit unit,boolean toRemove){
		DataLock dataLock =  DataLockMap.get(key);  //最大可能获取触发数据
		Object obj = null;
		if(dataLock != null) {
			obj = dataLock.getData(time, unit);
			if(toRemove) {DataLockMap.remove(key);}
		}
		return obj;
	}
	
	public Object getData(String key) {
		DataLock dataLock = DataLockMap.get(key);
		if(dataLock != null) {
			return dataLock.getData();
		}
		return null;
	}
	
	public boolean setData(String key,Object obj){
		DataLock dataLock = DataLockMap.get(key);
		if(dataLock != null){
			dataLock.setData(obj);
			return true;
		}
		return false;
	}
	
	public class DataLock {
		
		 Lock lock;
		 Condition condition;
		 Object data;			//数据
		 Date createDate;
		 
		 public DataLock(){
			 this.lock = new ReentrantLock();
			 this.condition = this.lock.newCondition();
			 this.createDate = new Date();
		 }
		 
		 public void await(Long time,TimeUnit unit){
			 this.lock.lock();
			 try {
				this.condition.await(time, unit);
			 } catch (Exception e) {
				e.printStackTrace();
			 }finally{
				this.lock.unlock();
			 }
		 }
		 
		 public void signalAll(){
			 this.lock.lock();
			 try {
				 this.condition.signalAll();
			 } catch (Exception e) {
				e.printStackTrace();
			 }finally{
				this.lock.unlock();
			 }
		 }
		 
		 public Object getData(Long time,TimeUnit unit) {
			 this.lock.lock();
			 try {
				 if(this.data == null) {
					 this.condition.await(time, unit);
				 }
			 } catch (Exception e) {
				e.printStackTrace();
			 }finally{
				this.lock.unlock();
			 }
			 return this.data;
		 }
		 
		 public Object getData() {
			 return this.data;
		 }
		 
		 public void shop() {
			 this.lock.lock();
			 try {
				 this.condition.signalAll();
			 } catch (Exception e) {
				e.printStackTrace();
			 }finally{
				this.lock.unlock();
			 }
		 }
		 
		 public void setData(Object data) {
			 this.lock.lock();
			 try {
				 this.data = data;
				 this.condition.signalAll();
			 } catch (Exception e) {
				e.printStackTrace();
			 }finally{
				this.lock.unlock();
			 }
		 }

		public Date getCreateDate() {
			return createDate;
		}
	}
	
	public class ExpireCheckTask extends TimerTask {
		
		final String key;
		final Date createDate;
		
		public ExpireCheckTask(String key) {
			this.key = key;
			this.createDate = new Date();
		}

		@Override
		public void run() {
			try {
				DataLock dataLock = DataLockMap.get(key);
				if(dataLock != null && (dataLock.getCreateDate().before(createDate) || dataLock.getCreateDate().equals(createDate))) {
					DataLockMap.remove(key);
					log.info("超时移除Key："+key+"，当前触发锁数量：" + DataLockMap.size());
					dataLock.shop();
				}
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
		
	}
}
